package lxs.swift.instance;


import java.util.*;
import java.util.function.BiFunction;
import java.util.stream.Collectors;

public class StructArray implements StructInstance<Integer>, Collection<Object> {
    private final List<Object> array;
    private final Actions<Integer> actions = new Actions<>(this);

    public StructArray(List<Object> list) {
        list.replaceAll(Types::structuring);
        this.array = list;
    }

    public StructArray() {
        this.array = new ArrayList<>();
    }

    @Override
    public Object of(Integer index) {
        Objects.requireNonNull(index);
        return this.array.get(index);
    }

    public void push(Object value) {
        Object structuring = Types.structuring(value);
        this.array.add(structuring);
    }

    @Override
    public void set(Integer index, Object value) {
        Objects.requireNonNull(index);
        Object structuring = Types.structuring(value);
        this.array.set(index, structuring);
    }

    @Override
    public Object delete(Integer index) {
        Objects.requireNonNull(index);
        return this.array.remove(index);
    }

    @Override
    public void retains(Integer... indexes) {
        Objects.requireNonNull(indexes);
        Set<Integer> indexSet = new HashSet<>(Arrays.asList(indexes));
        List<Object> newList = new ArrayList<>();
        indexSet.forEach(i -> newList.add(this.array.get(i)));
        this.array.clear();
        this.array.addAll(newList);
    }

    @Override
    public void iterate(BiFunction<Integer, Object, Boolean> function) {
        for (int i = 0; i < this.array.size(); i++) {
            Boolean apply = function.apply(i, this.array.get(i));
            if (!apply) return;
        }
    }

    @Override
    public Actions<Integer> action() {
        return actions;
    }

    @Override
    public int size() {
        return this.array.size();
    }

    @Override
    public boolean isEmpty() {
        return this.array.isEmpty();
    }

    @Override
    public boolean contains(Object o) {
        return this.array.contains(o);
    }

    @Override
    public Iterator<Object> iterator() {
        return this.array.iterator();
    }

    @Override
    public Object[] toArray() {
        return this.array.toArray();
    }

    @Override
    public <T> T[] toArray(T[] a) {
        return this.array.toArray(a);
    }

    @Override
    public boolean add(Object value) {
        Object structuring = Types.structuring(value);
        return this.array.add(structuring);
    }

    @Override
    public boolean remove(Object value) {
        Object structuring = Types.structuring(value);
        return this.array.remove(structuring);
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        Set<Object> set = c.stream().map(Types::structuring).collect(Collectors.toSet());
        return new HashSet<>(this.array).containsAll(set);
    }

    @Override
    public boolean addAll(Collection<?> c) {
        List<Object> collect = c.stream().map(Types::structuring).collect(Collectors.toList());
        return this.array.addAll(collect);
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        List<Object> collect = c.stream().map(Types::structuring).collect(Collectors.toList());
        return this.array.removeAll(collect);
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        List<Object> collect = c.stream().map(Types::structuring).collect(Collectors.toList());
        return this.array.retainAll(collect);
    }

    @Override
    public void clear() {
        this.array.clear();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof StructArray)) return false;
        StructArray array1 = (StructArray) o;
        return Objects.equals(array, array1.array);
    }

    @Override
    public int hashCode() {
        return Objects.hash(array);
    }

    @Override
    public String toString() {
        return array.toString();
    }
}
